package c.c.d.s.s.o.c.as.configuration;

import c.c.d.s.s.o.c.as.configuration.support.client.CustomWebResponseExceptionTranslator;
import c.c.d.s.s.o.c.as.configuration.support.token.granter.CustomTokenGranter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.Sets;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;

/**
 * 用 FastJson 作为 {@link HttpMessageConverter}
 *
 * @author LiKe
 * @version 1.0.0
 * @date 2020-05-25 15:43
 */
@Configuration
public class HttpMessageConverterConfiguration {

    @Bean
    public HttpMessageConverter<?> httpMessageConvertConfigurer() {

        // ~ FastJsonConfig
        final FastJsonConfig config = new FastJsonConfig();
        config.setSerializerFeatures(
                // 保留 Map 空的字段
                SerializerFeature.WriteMapNullValue,
                // 将 String类型的 null 转成 ""
                SerializerFeature.WriteNullStringAsEmpty,
                // 将 Number类型的 null 转成 0
                SerializerFeature.WriteNullNumberAsZero,
                // 将 List类型的 null 转成 []
                SerializerFeature.WriteNullListAsEmpty,
                // 将 Boolean 类型的 null 转成 false
                SerializerFeature.WriteNullBooleanAsFalse,
                // 避免循环引用
                SerializerFeature.DisableCircularReferenceDetect
        );
        config.setDateFormat("yyyy-MM-dd HH:mm:ss");

        // ~ FastJsonHttpMessageConverter
        final FastJsonHttpMessageConverter converter = new CustomFastJsonHttpMessageConverter(
                CustomWebResponseExceptionTranslator.CustomOAuth2Exception.class,
                CustomTokenGranter.CustomOAuth2AccessToken.class
        );
        converter.setFastJsonConfig(config);
        converter.setDefaultCharset(StandardCharsets.UTF_8);
        // 相当于在 Controller 上的 @RequestMapping 中的 produces = "application/json"
        converter.setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_JSON));
        return converter;
    }

    /**
     * 自定义的 {@link FastJsonHttpMessageConverter}<br>
     * 　默认的 {@link FastJsonHttpMessageConverter} 的 supports 方法始终返回 true, 对于某些逻辑可能不需要应用到此 Converter
     *
     * @author LiKe
     * @date 2020-06-23 09:51:00
     */
    @Slf4j
    private static final class CustomFastJsonHttpMessageConverter extends FastJsonHttpMessageConverter {

        /**
         * 不支持的列表
         */
        private final Set<Class<?>> excludes;

        public CustomFastJsonHttpMessageConverter(Class<?>... clazzArr) {
            this.excludes = Sets.newHashSet(Arrays.asList(clazzArr));
        }

        @Override
        protected boolean supports(Class<?> clazz) {
            return !excludes.contains(clazz);
        }
    }
}